home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-06-23 | 31.8 KB | 1,099 lines |
- //////////
- //
- // File: QTText.c
- //
- // Contains: QuickTime text media handler sample code.
- //
- // Written by: Tim Monroe
- // parts based on QTTextSample code by Nick Thompson (see develop, issue 20).
- //
- // Copyright: © 1995-1998 by Apple Computer, Inc., all rights reserved.
- //
- // Change History (most recent first):
- //
- // <9> 06/14/99 rtm added a bunch more chapter track utilities
- // <8> 06/11/99 rtm added QTText_GetChapterTrackForTrack
- // <7> 06/10/98 rtm general clean-up; in QTText_AddTextTrack, set the time scale of the
- // text track media to that of the movie
- // <6> 06/08/98 rtm fixed text track duration calculations
- // <5> 06/05/98 rtm fixed track geometry calculations in QTText_AddTextTrack
- // <4> 06/03/98 rtm added QTText_AddTextTrack and QTText_RemoveIndTextTrack; borrowed
- // QTText_CopyCStringToPascal from source file CGlue.c
- // <3> 05/29/98 rtm added chapter track enabling/disabling
- // <2> 04/08/98 rtm added text offset handling, so we can now search within the current sample;
- // added QTText_EditText to allow editing a sample's text; added compile flag
- // to use MovieSearchText instead of TextMediaFindNextText (see Note 3)
- // <1> 04/07/98 rtm first file; conversion to personal coding style; updated to latest headers;
- // got basic searching working on Mac and Windows
- //
- // This source code shows how to do searches on text media, how to use a simple text procedure to retrieve
- // the text from a text media sample, and how to edit that text. It also shows how to convert a text track
- // into a chapter track (and vice versa), and how to add (and remove) text tracks to (and from) a movie.
- //
- // NOTES:
- //
- // *** (1) ***
- // This code is based in part on the code provided with the develop article on QuickTime text by Nick Thompson
- // (issue 20). Make sure to read that article for complete details on the techniques employed here. I have
- // taken the liberty of reworking that code as necessary to make it run on Windows platforms and to bring it
- // into line with the other QuickTime code samples.
- //
- // *** (2) ***
- // The editted text does NOT use the font, size, color, justification, or background color of the text
- // it replaces. It would be straightforward to add this capability. See the develop article mentioned above for
- // code that does all these things.
- //
- // *** (3) ***
- // The Movie Toolbox provides two different functions that you can use to search for text in a text track:
- // TextMediaFindNextText (originally called FindNextText) and MovieSearchText. TextMediaFindNextText inspects
- // only a specified track, while MovieSearchText can search all text tracks in a specified movie. Moreover,
- // MovieSearchText will automatically go to and highlight the found text; these operations must be done manually
- // if you're using TextMediaFindNextText. This sample code illustrates BOTH of these functions; you determine
- // which is used by setting the USE_MOVIESEARCHTEXT compiler flag in QTText.h.
- //
- //////////
-
- #include "QTText.h"
-
-
- //////////
- //
- // global variables
- //
- //////////
-
- Boolean gSearchForward = true; // do we search forward or backward?
- Boolean gSearchWrap = true; // do we wrap around when searching?
- Boolean gSearchWithCase = false; // is the search case sensitive?
- Str255 gSearchText; // the text we're searching for
- Str255 gSampleText; // the text of the current text media sample
- long gOffset; // offset of current found text within sample
-
- extern ModalFilterUPP gModalFilterUPP;
-
-
- //////////
- //
- // QTText_InitWindowData
- // Initialize any window-specific data for the text media handler.
- //
- //////////
-
- ApplicationDataHdl QTText_InitWindowData (WindowObject theWindowObject)
- {
- ApplicationDataHdl myAppData = NULL;
- Track myTrack = NULL;
- MediaHandler myHandler = NULL;
-
- myAppData = (ApplicationDataHdl)NewHandleClear(sizeof(ApplicationDataRecord));
- if (myAppData != NULL) {
-
- myTrack = GetMovieIndTrackType((**theWindowObject).fMovie, 1, TextMediaType, movieTrackMediaType | movieTrackEnabledOnly);
- if (myTrack != NULL) {
- // load the entire text track into RAM
- LoadTrackIntoRam(myTrack, 0L, GetTrackDuration(myTrack), 0L);
-
- // set the text handling procedure
- myHandler = GetMediaHandler(GetTrackMedia(myTrack));
- if (myHandler != NULL)
- TextMediaSetTextProc(myHandler, NewTextMediaProc(QTText_TextProc), (long)theWindowObject);
- }
-
- // remember the text track and media handler
- (**myAppData).fMovieHasText = (myTrack != NULL);
- (**myAppData).fTextIsChapter = QTText_TrackTypeHasAChapterTrack((**theWindowObject).fMovie, VideoMediaType);
- (**myAppData).fTextTrack = myTrack;
- (**myAppData).fTextHandler = myHandler;
- }
-
- return(myAppData);
- }
-
-
- //////////
- //
- // QTText_DumpWindowData
- // Get rid of any window-specific data for the text media handler.
- //
- //////////
-
- void QTText_DumpWindowData (WindowObject theWindowObject)
- {
- ApplicationDataHdl myAppData = NULL;
-
- myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
- if (myAppData != NULL)
- DisposeHandle((Handle)myAppData);
- }
-
-
- //////////
- //
- // QTText_SetSearchText
- // Let the user specify the text to be searched for.
- //
- //////////
-
- void QTText_SetSearchText (void)
- {
- DialogPtr myDialog;
- short myItem;
- short myType;
- Handle myItemHandle;
- Rect myRect;
-
- // get the dialog that lets the user specify the search text
- myDialog = GetNewDialog(kTextDialogID, NULL, (WindowPtr)-1);
- if (myDialog == NULL)
- goto bail;
-
- SetDialogDefaultItem(myDialog, kTextOKIndex);
-
- // set the current search text into the edittext field
- GetDialogItem(myDialog, kTextTextEditIndex, &myType, &myItemHandle, &myRect);
- SetDialogItemText(myItemHandle, gSearchText);
- SelectDialogItemText(myDialog, kTextTextEditIndex, 0, 32767);
-
- // now show the dialog
- MacShowWindow(myDialog);
- MacSetPort((GrafPtr)myDialog);
-
- do {
- ModalDialog(gModalFilterUPP, &myItem);
- } while (myItem != kTextOKIndex);
-
- // get the text in the edittext field
- GetDialogItemText(myItemHandle, gSearchText);
-
- bail:
- if (myDialog != NULL)
- DisposeDialog(myDialog);
- }
-
-
- //////////
- //
- // QTText_FindText
- // Find the specified string in the (first) text track of the specified window object.
- //
- //////////
-
- void QTText_FindText (WindowObject theWindowObject, Str255 theText)
- {
- ApplicationDataHdl myAppData;
- Movie myMovie;
- MediaHandler myHandler = NULL;
- MovieController myMC = NULL;
- long myFlags = 0L;
- TimeValue myTimeValue;
- OSErr myErr = noErr;
-
- myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
- if (myAppData == NULL)
- goto bail;
-
- myMC = (**theWindowObject).fController;
- myMovie = (**theWindowObject).fMovie;
- myHandler = (**myAppData).fTextHandler;
-
- // set the search features
- myFlags = findTextUseOffset;
-
- if (!gSearchForward)
- myFlags |= findTextReverseSearch;
-
- if (gSearchWrap)
- myFlags |= findTextWrapAround;
-
- if (gSearchWithCase)
- myFlags |= findTextCaseSensitive;
-
- #if USE_MOVIESEARCHTEXT
- //////////
- //
- // METHOD ONE: Use MovieSearchText, your one-stop, find-the-text-and-do-the-right-thing function.
- //
- //////////
-
- myFlags |= searchTextEnabledTracksOnly;
- myTimeValue = GetMovieTime(myMovie, NULL);
-
- myErr = MovieSearchText(myMovie, (Ptr)(&theText[1]), theText[0], myFlags, NULL, &myTimeValue, &gOffset);
- if (myErr != noErr)
- DoBeep(); // if the desired string wasn't found, beep
- #else
- //////////
- //
- // METHOD TWO: Use TextMediaFindNextText. Here, you need to explicitly go to the found text and select it.
- //
- //////////
-
- if (myHandler != NULL) {
- TimeValue myFoundTime, myFoundDuration;
- TimeRecord myNewTime;
- RGBColor myColor;
-
- myColor.red = myColor.green = myColor.blue = 0x8000; // grey
-
- // search for the specified text
- myErr = TextMediaFindNextText(myHandler, (Ptr)(&theText[1]), theText[0], myFlags, GetMovieTime(myMovie, NULL), &myFoundTime, &myFoundDuration, &gOffset);
- if (myFoundTime != -1) {
- // convert the TimeValue to a TimeRecord
- myNewTime.value.hi = 0;
- myNewTime.value.lo = myFoundTime;
- myNewTime.scale = GetMovieTimeScale(myMovie);
- myNewTime.base = NULL;
-
- // go to the found text
- MCDoAction(myMC, mcActionGoToTime, &myNewTime);
-
- // highlight the text
- TextMediaHiliteTextSample(myHandler, myFoundTime, gOffset, gOffset + theText[0], &myColor);
-
- } else {
- // if the desired string wasn't found, beep
- DoBeep();
- }
- }
- #endif // USE_MOVIESEARCHTEXT
-
- // update the current offset, if we're searching forward
- if (gSearchForward && (myErr == noErr))
- gOffset += theText[0];
-
- bail:
- ;
- }
-
-
- //////////
- //
- // QTText_EditText
- // Edit the text in the current sample of the (first) text track of the specified window object.
- //
- //////////
-
- void QTText_EditText (WindowObject theWindowObject)
- {
- ApplicationDataHdl myAppData = NULL;
- Movie myMovie;
- Track myTrack;
- Media myMedia;
- MediaHandler myHandler = NULL;
- DialogPtr myDialog = NULL;
- short myItem;
- short myType;
- Handle myItemHandle = NULL;
- Rect myRect;
- OSErr myErr = noErr;
-
- // get the movie and related stuff
- myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
- if (myAppData == NULL)
- goto bail;
-
- myMovie = (**theWindowObject).fMovie;
- myTrack = (**myAppData).fTextTrack;
- myMedia = GetTrackMedia(myTrack);
- myHandler = (**myAppData).fTextHandler;
-
- // get the dialog that lets the user specify the text for the current sample
- myDialog = GetNewDialog(kEditDialogID, NULL, (WindowPtr)-1);
- if (myDialog == NULL)
- goto bail;
-
- SetDialogDefaultItem(myDialog, kEditOKIndex);
- SetDialogCancelItem(myDialog, kEditCancelIndex);
-
- // set the current sample text into the edittext field
- GetDialogItem(myDialog, kEditTextEditIndex, &myType, &myItemHandle, &myRect);
- SetDialogItemText(myItemHandle, gSampleText);
- SelectDialogItemText(myDialog, kEditTextEditIndex, 0, 32767);
-
- // now show the dialog
- MacShowWindow(myDialog);
- MacSetPort((GrafPtr)myDialog);
-
- do {
- ModalDialog(gModalFilterUPP, &myItem);
- } while ((myItem != kEditOKIndex) && (myItem != kEditCancelIndex));
-
- // if the user hit the OK button, save the text and update the text sample
- if (myItem == kEditOKIndex) {
- Fixed myWidth;
- Fixed myHeight;
- Rect myBounds;
- TimeValue myMovieTime;
- TimeValue mySampleTime;
- TimeValue myDuration;
- TimeValue myMediaSampleDuration;
- TimeValue myMediaSampleStartTime;
- TimeValue myMediaCurrentTime;
- TimeValue myInterestingTime;
- long myMediaSampleIndex;
-
- // get the text in the edittext field
- GetDialogItemText(myItemHandle, gSampleText);
-
- // install that text as the current text media sample
-
- // first, we need to find the start and duration for this media sample;
- // get the current movie time and the time in media time of the current sample
- myMovieTime = GetMovieTime(myMovie, NULL);
- if (myMovieTime < 0)
- goto bail;
-
- myMediaCurrentTime = TrackTimeToMediaTime(myMovieTime, myTrack);
-
- // get detailed information about the start and duration of the current sample
- MediaTimeToSampleNum( myMedia,
- myMediaCurrentTime,
- &myMediaSampleIndex,
- &myMediaSampleStartTime,
- &myMediaSampleDuration);
-
- // see where this text starts
- GetTrackNextInterestingTime(myTrack, nextTimeEdgeOK | nextTimeMediaSample, myMovieTime, -fixed1, &myInterestingTime, NULL);
- myMovieTime = myInterestingTime;
- GetTrackNextInterestingTime(myTrack, nextTimeEdgeOK | nextTimeMediaSample, myMovieTime, fixed1, &myInterestingTime, &myDuration);
-
- myErr = BeginMediaEdits(myMedia);
- if (myErr != noErr)
- goto bail;
-
- // delete the existing text
- myErr = DeleteTrackSegment(myTrack, myInterestingTime, myDuration);
- if (myErr != noErr)
- goto bail;
-
- // get the track bounds
- GetTrackDimensions(myTrack, &myWidth, &myHeight);
- myBounds.top = 0;
- myBounds.left = 0;
- myBounds.right = Fix2Long(myWidth);
- myBounds.bottom = Fix2Long(myHeight);
-
- // write out the new data to the media
- myErr = TextMediaAddTextSample( myHandler,
- (Ptr)(&gSampleText[1]),
- gSampleText[0],
- 0,
- 0,
- 0,
- NULL,
- NULL,
- teCenter,
- &myBounds,
- dfClipToTextBox,
- 0,
- 0,
- 0,
- NULL,
- myMediaSampleDuration,
- &mySampleTime);
-
- if (myErr != noErr)
- goto bail;
-
- // insert the new media into the track
- InsertMediaIntoTrack(myTrack, myInterestingTime, mySampleTime, myMediaSampleDuration, fixed1);
- EndMediaEdits(myMedia);
-
- // stamp the movie as dirty
- (**theWindowObject).fDirty = true;
- }
-
- bail:
- if (myDialog != NULL)
- DisposeDialog(myDialog);
- }
-
-
- //////////
- //
- // QTText_TextProc
- // This function is called whenever a new text sample is about to be displayed.
- // We'll use it to grab the text of the current text sample.
- //
- // NOTE: The theRefCon parameter is a handle to a window object record.
- //
- //////////
-
- PASCAL_RTN OSErr QTText_TextProc (Handle theText, Movie theMovie, short *theDisplayFlag, long theRefCon)
- {
- char *myTextPtr = NULL;
- short myTextSize;
- short myIndex;
-
- // on entry to this function, theText is a handle to the formatted text,
- // which is a big-endian 16-bit length word followed by the text itself
- myTextSize = EndianU16_BtoN(*(short *)(*theText));
- myTextPtr = (char *)(*theText + sizeof(short));
-
- // copy the text into our global variable
- for (myIndex = 1; myIndex <= myTextSize; myIndex++, myTextPtr++)
- gSampleText[myIndex] = *myTextPtr;
-
- gSampleText[0] = myTextSize;
-
- // ask for the default text display
- *theDisplayFlag = txtProcDefaultDisplay;
-
- return(noErr);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Text track utilities.
- //
- // Use these functions to manipulate text tracks in a movie.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // QTText_AddTextTrack
- // Add a text track containing some text data to a movie; return the new track to the caller.
- //
- // The theStrings parameter is an array of C strings; each element is the text for a certain span of frames
- // of the movie. The theFrames parameter is an array of frame counts; each of these counts determines how many
- // frames the corresponding text element in the theStrings array applies to; the sum of all the values in this
- // array should be equal to the total number of frames in the movie.
- //
- // If the isChapterTrack parameter is true, the text track is set to be a chapter track, attached to the (first)
- // track of type theType.
- //
- //////////
-
- Track QTText_AddTextTrack (Movie theMovie, char *theStrings[], short theFrames[], short theNumFrames, OSType theType, Boolean isChapterTrack)
- {
- Track myTypeTrack = NULL;
- Track myTextTrack = NULL;
- Media myMedia;
- MediaHandler myHandler = NULL;
- TimeScale myTimeScale;
- MatrixRecord myMatrix;
- Fixed myWidth;
- Fixed myHeight;
- OSErr myErr = noErr;
-
- //////////
- //
- // find the target track
- //
- //////////
-
- // get the (first) track of the specified type; this track determines the width of the new text track
- // and (if isChapterTrack is true) is the target of the new chapter track
- myTypeTrack = GetMovieIndTrackType(theMovie, 1, theType, movieTrackMediaType);
- if (myTypeTrack == NULL)
- goto bail;
-
- // get the dimensions of the target track
- GetTrackDimensions(myTypeTrack, &myWidth, &myHeight);
- myTimeScale = GetMediaTimeScale(GetTrackMedia(myTypeTrack));
-
- //////////
- //
- // create the text track and media
- //
- //////////
-
- myTextTrack = NewMovieTrack(theMovie, myWidth, FixRatio(kTextTrackHeight, 1), kNoVolume);
- myMedia = NewTrackMedia(myTextTrack, TextMediaType, myTimeScale, NULL, 0);
- myHandler = GetMediaHandler(myMedia);
-
- //////////
- //
- // figure out the text track geometry
- //
- //////////
-
- GetTrackMatrix(myTextTrack, &myMatrix);
- TranslateMatrix(&myMatrix, 0, myHeight);
-
- SetTrackMatrix(myTextTrack, &myMatrix);
- SetTrackEnabled(myTextTrack, true);
-
- //////////
- //
- // edit the track media
- //
- //////////
-
- myErr = BeginMediaEdits(myMedia);
- if (myErr == noErr) {
- Rect myBounds;
- short myIndex;
- TimeValue myTypeSampleDuration;
- TimeRecord myTimeRec;
-
- myBounds.top = 0;
- myBounds.left = 0;
- myBounds.right = Fix2Long(myWidth);
- myBounds.bottom = Fix2Long(myHeight);
-
- // determine the duration of a sample in the track of the specified type
- myTypeSampleDuration = QTUtils_GetFrameDuration(myTypeTrack);
-
-
- for (myIndex = 0; myIndex < theNumFrames; myIndex++) {
- TimeValue myTextSampleDuration;
- TimeValue mySampleTime;
- Str255 mySampleText;
-
- myTextSampleDuration = myTypeSampleDuration * theFrames[myIndex];
-
- // set the time scale of the media to that of the movie
- myTimeRec.value.lo = myTextSampleDuration;
- myTimeRec.value.hi = 0;
- myTimeRec.scale = GetMovieTimeScale(theMovie);
- ConvertTimeScale(&myTimeRec, GetMediaTimeScale(myMedia));
- myTextSampleDuration = myTimeRec.value.lo;
-
- QTText_CopyCStringToPascal(theStrings[myIndex], mySampleText);
-
- // write out the new data to the media
- myErr = TextMediaAddTextSample( myHandler,
- (Ptr)(&mySampleText[1]),
- mySampleText[0],
- 0,
- 0,
- 0,
- NULL,
- NULL,
- teCenter,
- &myBounds,
- dfClipToTextBox,
- 0,
- 0,
- 0,
- NULL,
- myTextSampleDuration,
- &mySampleTime);
- }
- }
-
- EndMediaEdits(myMedia);
-
- // insert the text media into the text track
- myErr = InsertMediaIntoTrack(myTextTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
-
- //////////
- //
- // if requested, set the new text track as a chapter track for the track of the specified type
- //
- //////////
-
- if (isChapterTrack)
- myErr = AddTrackReference(myTypeTrack, myTextTrack, kTrackReferenceChapterList, NULL);
-
- bail:
- return(myTextTrack);
- }
-
-
- //////////
- //
- // QTText_RemoveIndTextTrack
- // Remove a text track, specified by its index, from a movie.
- //
- // If theIndex is kAllTextTracks (0), remove all text tracks from the movie.
- //
- //////////
-
- OSErr QTText_RemoveIndTextTrack (Movie theMovie, short theIndex)
- {
- Track myTrack = NULL;
- OSErr myErr = noErr;
-
- if (theIndex == kAllTextTracks) {
- // remove ALL text tracks from the movie
- myTrack = GetMovieIndTrackType(theMovie, 1, TextMediaType, movieTrackMediaType);
- if (myTrack == NULL)
- myErr = badTrackIndex;
-
- while (myTrack != NULL) {
- QTUtils_DeleteAllReferencesToTrack(myTrack);
- DisposeMovieTrack(myTrack);
- myTrack = GetMovieIndTrackType(theMovie, 1, TextMediaType, movieTrackMediaType);
- }
- } else {
- // remove ONE text track from the movie
- myTrack = GetMovieIndTrackType(theMovie, theIndex, TextMediaType, movieTrackMediaType);
- if (myTrack == NULL) {
- myErr = badTrackIndex;
- } else {
- QTUtils_DeleteAllReferencesToTrack(myTrack);
- DisposeMovieTrack(myTrack);
- }
- }
-
- return(myErr);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Chapter track utilities.
- //
- // Use these functions to manipulate chapter tracks in a movie.
- //
- // A chapter track is a text track that has been associated with some other track (often a video or sound
- // track) in such a way that the movie controller will build, display, and handle a pop-up menu of titles
- // of various parts of the associated track. The pop-up menu appears (space permitting) in the controller
- // bar. The various parts of the associated track are called the track's "chapters". When a user selects a
- // chapter title in the pop-up menu, the movie controller jumps to the start time of the selected chapter.
- //
- // You create the association between a text track and some other track by creating a reference from that
- // other track to the text track, where the reference is of type kTrackReferenceChapterList. Note that all
- // the chapter titles must be contained in a single text track; you specify the starting time for chapters
- // when you add the text to the text track by calling TextMediaAddTextSample. Note also that you need to
- // create the chapter association only between the text track and one other track, not between the chapter
- // track and all other tracks in the movie. (That "other" track must be enabled, but typically the chapter
- // track is not enabled.)
- //
- // The pop-up menu will disappear from the controller bar if there isn't enough space to display the menu,
- // the volume slider control, the step buttons, and the other controls.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // QTText_SetTextTrackAsChapterTrack
- // Set the (first) text track in the specified movie to be or not to be a chapter track
- // for the (first) enabled track of the specified type.
- //
- // The isChapterTrack parameter determines the final state of the text track.
- //
- //////////
-
- OSErr QTText_SetTextTrackAsChapterTrack (WindowObject theWindowObject, OSType theType, Boolean isChapterTrack)
- {
- ApplicationDataHdl myAppData = NULL;
- Movie myMovie = NULL;
- MovieController myMC = NULL;
- Track myTypeTrack = NULL;
- Track myTextTrack = NULL;
- OSErr myErr = paramErr;
-
- // get the movie, controller, and related stuff
- myAppData = (ApplicationDataHdl)GetAppDataFromWindowObject(theWindowObject);
- if (myAppData == NULL)
- goto bail;
-
- myMovie = (**theWindowObject).fMovie;
- myMC = (**theWindowObject).fController;
- myTextTrack = (**myAppData).fTextTrack;
-
- if ((myMovie != NULL) && (myMC != NULL)) {
- myTypeTrack = GetMovieIndTrackType(myMovie, 1, theType, movieTrackMediaType | movieTrackEnabledOnly);
- if ((myTypeTrack != NULL) && (myTextTrack != NULL)) {
-
- // add or delete a track reference, as determined by the desired final state
- if (isChapterTrack)
- myErr = AddTrackReference(myTypeTrack, myTextTrack, kTrackReferenceChapterList, NULL);
- else
- myErr = DeleteTrackReference(myTypeTrack, kTrackReferenceChapterList, 1);
-
- // tell the movie controller we've changed aspects of the movie
- MCMovieChanged(myMC, myMovie);
-
- // stamp the movie as dirty
- (**theWindowObject).fDirty = true;
- }
- }
-
- bail:
- return(myErr);
- }
-
-
- //////////
- //
- // QTText_TrackTypeHasAChapterTrack
- // Does the (first) enabled track of the specified type in the specified movie have a chapter track?
- //
- //////////
-
- Boolean QTText_TrackTypeHasAChapterTrack (Movie theMovie, OSType theType)
- {
- Track myTypeTrack = NULL;
- Track myTextTrack = NULL;
-
- myTypeTrack = GetMovieIndTrackType(theMovie, 1, theType, movieTrackMediaType | movieTrackEnabledOnly);
- if (myTypeTrack != NULL)
- myTextTrack = GetTrackReference(myTypeTrack, kTrackReferenceChapterList, 1);
-
- return(myTextTrack != NULL);
- }
-
-
- //////////
- //
- // QTText_TrackHasAChapterTrack
- // Does the specified track have a chapter track?
- //
- //////////
-
- Boolean QTText_TrackHasAChapterTrack (Track theTrack)
- {
- return(GetTrackReference(theTrack, kTrackReferenceChapterList, 1) != NULL);
- }
-
-
- //////////
- //
- // QTText_MovieHasAChapterTrack
- // Does the specified movie have a chapter track? In other words, is there are least one enabled track
- // in the specified movie that has a chapter track associated wih it?
- //
- //////////
-
- Boolean QTText_MovieHasAChapterTrack (Movie theMovie)
- {
- long myCount;
- long myTrackCount = GetMovieTrackCount(theMovie);
- Track myTrack = NULL;
- Boolean myGotChapter = false;
-
- for (myCount = 1; myCount <= myTrackCount; myCount++) {
- myTrack = GetMovieIndTrack(theMovie, myCount);
- if (GetTrackEnabled(myTrack))
- myGotChapter = QTText_TrackHasAChapterTrack(myTrack);
- if (myGotChapter)
- break;
- }
-
- return(myGotChapter);
- }
-
-
- //////////
- //
- // QTText_GetChapterTrackForTrack
- // Return the first chapter track (if any) associated with the specified track.
- //
- //////////
-
- Track QTText_GetChapterTrackForTrack (Track theTrack)
- {
- return(GetTrackReference(theTrack, kTrackReferenceChapterList, 1));
- }
-
-
- //////////
- //
- // QTText_GetChapterTrackForMovie
- // Return the first chapter track (if any) in the specified movie.
- //
- // A movie can have more than one chapter track; if so, QuickTime uses the chapter track associated
- // with the first enabled track that it finds. Accordingly, this function returns the first chapter
- // track that we find as we iterate thru the movie's tracks.
- //
- //////////
-
- Track QTText_GetChapterTrackForMovie (Movie theMovie)
- {
- long myCount;
- long myTrackCount = GetMovieTrackCount(theMovie);
- Track myTrack = NULL;
- Track myChapTrack = NULL;
-
- for (myCount = 1; myCount <= myTrackCount; myCount++) {
- myTrack = GetMovieIndTrack(theMovie, myCount);
- if (GetTrackEnabled(myTrack))
- myChapTrack = QTText_GetChapterTrackForTrack(myTrack);
- if (myChapTrack != NULL)
- break;
- }
-
- return(myChapTrack);
- }
-
-
- //////////
- //
- // QTText_IsChapterTrack
- // Is the specified track a chapter track?
- //
- //////////
-
- Boolean QTText_IsChapterTrack (Track theTrack)
- {
- Movie myMovie = NULL;
- Track myTrack = NULL;
- long myTrackCount = 0L;
- long myTrRefCount = 0L;
- long myTrackIndex;
- long myTrRefIndex;
- Boolean isChapTrack = false;
-
- myMovie = GetTrackMovie(theTrack);
- if (myMovie == NULL)
- goto bail;
-
- // a chapter track is a text track that is referred to by some other track in the movie,
- // so we need to iterate thru all those tracks to see if any of them refers to the specified track
- myTrackCount = GetMovieTrackCount(myMovie);
- for (myTrackIndex = 1; myTrackIndex <= myTrackCount; myTrackIndex++) {
- myTrack = GetMovieIndTrack(myMovie, myTrackIndex);
- if ((myTrack != NULL) && (myTrack != theTrack)) {
-
- // iterate thru all track references of type kTrackReferenceChapterList
- myTrRefCount = GetTrackReferenceCount(myTrack, kTrackReferenceChapterList);
- for (myTrRefIndex = 1; myTrRefIndex <= myTrRefCount; myTrRefIndex++) {
- Track myRefTrack = NULL;
-
- myRefTrack = GetTrackReference(myTrack, kTrackReferenceChapterList, myTrRefIndex);
- if (myRefTrack == theTrack) {
- isChapTrack = true;
- goto bail;
- }
- }
- }
- }
-
- bail:
- return(isChapTrack);
- }
-
-
- //////////
- //
- // QTText_GetFirstChapterTime
- // Return, through the theTime parameter, the starting time of the first chapter of the
- // specified chapter track.
- //
- // If this function encounters an error, it returns a (bogus) starting time of -1. Note that
- // GetTrackNextInterestingTime also returns -1 as a starting time if the search criteria
- // specified in the myFlags parameter are not matched by any interesting time in the movie.
- //
- //////////
-
- OSErr QTText_GetFirstChapterTime (Track theChapterTrack, TimeValue *theTime)
- {
- short myFlags = nextTimeMediaSample + nextTimeEdgeOK; // we want the first sample in the movie
-
- if (theChapterTrack == NULL) {
- *theTime = kBogusStartingTime; // a bogus time
- return(invalidTrack);
- }
-
- GetTrackNextInterestingTime(theChapterTrack, myFlags, (TimeValue)0, fixed1, theTime, NULL);
- return(GetMoviesError());
- }
-
-
- //////////
- //
- // QTText_GetNextChapterTime
- // Return, through the theTime parameter, the starting time of the chapter of the
- // specified chapter track that immediately follows the chapter starting at the time
- // passed in through theTime.
- //
- //////////
-
- OSErr QTText_GetNextChapterTime (Track theChapterTrack, TimeValue *theTime)
- {
- short myFlags = nextTimeMediaSample; // we want the next sample in the movie
-
- if (theChapterTrack == NULL) {
- *theTime = kBogusStartingTime; // a bogus time
- return(invalidTrack);
- }
-
- GetTrackNextInterestingTime(theChapterTrack, myFlags, *theTime, fixed1, theTime, NULL);
- return(GetMoviesError());
- }
-
-
- //////////
- //
- // QTText_GetIndChapterTime
- // Return the starting time of the chapter in the specified chapter track that has the specified index.
- //
- //////////
-
- TimeValue QTText_GetIndChapterTime (Track theChapterTrack, long theIndex)
- {
- long myCount = 1;
- TimeValue myTime = kBogusStartingTime;
-
- if ((theChapterTrack == NULL) || (theIndex < 1))
- return(myTime);
-
- QTText_GetFirstChapterTime(theChapterTrack, &myTime);
- if (theIndex == 1)
- return(myTime);
-
- while (myCount < theIndex) {
- QTText_GetNextChapterTime(theChapterTrack, &myTime);
- myCount++;
- }
-
- return(myTime);
- }
-
-
- //////////
- //
- // QTText_GetIndChapterText
- // Return the text of the chapter in the specified chapter track that has the specified index.
- //
- // The caller is responsible for disposing of the pointer returned by this function (by calling free).
- //
- //////////
-
- char *QTText_GetIndChapterText (Track theChapterTrack, long theIndex)
- {
- long myCount = 1;
- long mySize; // size of entire handle returned, which may include appended style atoms
- short myTextSize;
- TimeValue myTime;
- Handle myHandle = NewHandleClear(0);
- char *myText = NULL;
-
- if ((theChapterTrack == NULL) || (theIndex < 1))
- return(myText);
-
- if (myHandle == NULL)
- return(myText);
-
- myTime = QTText_GetIndChapterTime(theChapterTrack, theIndex);
- if (myTime != kBogusStartingTime) {
-
- GetMediaSample( GetTrackMedia(theChapterTrack),
- myHandle,
- 0,
- &mySize,
- TrackTimeToMediaTime(myTime, theChapterTrack), // media time scale
- NULL,
- NULL,
- NULL,
- NULL,
- 0,
- NULL,
- NULL);
-
- // for text media samples, the returned handle is a 16-bit size field followed by the actual text data
- myTextSize = *(short *)(*myHandle);
- myText = malloc(myTextSize + 1);
- BlockMove(*myHandle + sizeof(short), myText, myTextSize);
- myText[myTextSize] = '\0';
-
- DisposeHandle(myHandle);
- }
-
- return(myText);
- }
-
-
- //////////
- //
- // QTText_GetChapterCount
- // Return the number of chapters in the specified chapter track.
- //
- //////////
-
- long QTText_GetChapterCount (Track theChapterTrack)
- {
- long myCount = 0;
- TimeValue myTime = kBogusStartingTime;
-
- if (theChapterTrack != NULL) {
- QTText_GetFirstChapterTime(theChapterTrack, &myTime);
-
- while (myTime != kBogusStartingTime) {
- myCount++;
- QTText_GetNextChapterTime(theChapterTrack, &myTime);
- }
- }
-
- return(myCount);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Miscellaneous utilities.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // QTText_CopyCStringToPascal
- // Convert the source C string to a destination Pascal string as it's copied.
- //
- // The destination string will be truncated to fit into a Str255 if necessary.
- // If the C string pointer is NULL, the Pascal string's length is set to zero.
- //
- // This routine is borrowed from CGlue.c, by Nick Kledzik.
- //
- //////////
-
- void QTText_CopyCStringToPascal (const char *theSrc, Str255 theDst)
- {
- short myLength = 0;
-
- // handle case of overlapping strings
- if ((void *)theSrc == (void *)theDst) {
- unsigned char *myCurDst = &theDst[1];
- unsigned char myChar;
-
- myChar = *(const unsigned char *)theSrc++;
- while (myChar != '\0') {
- unsigned char myNextChar;
-
- // use myNextChar so we don't overwrite what we are about to read
- myNextChar = *(const unsigned char *)theSrc++;
- *myCurDst++ = myChar;
- myChar = myNextChar;
-
- if (++myLength >= 255)
- break;
- }
- } else if (theSrc != NULL) {
- unsigned char *myCurDst = &theDst[1];
- short myOverflow = 255; // count down, so test it loop is faster
- register char myTemp;
-
- // we can't do the K&R C thing of “while (*s++ = *t++)” because it will copy the trailing zero,
- // which might overrun the Pascal buffer; instead, we use a temp variable
- while ((myTemp = *theSrc++) != 0) {
- *(char *)myCurDst++ = myTemp;
-
- if (--myOverflow <= 0)
- break;
- }
- myLength = 255 - myOverflow;
- }
-
- // set the length of the destination Pascal string
- theDst[0] = myLength;
- }
-
-
- //////////
- //
- // QTText_UpdateMovieAndController
- // Synchronize the movie and controller.
- //
- //////////
-
- void QTText_UpdateMovieAndController (MovieController theMC)
- {
- Movie myMovie = NULL;
- Rect myRect;
-
- myMovie = MCGetMovie(theMC);
-
- // we must make sure that we are still top-left aligned
- GetMovieBox(myMovie, &myRect);
- MacOffsetRect(&myRect, -myRect.left, -myRect.top);
- SetMovieBox(myMovie, &myRect);
-
- MCDoAction(theMC, mcActionMovieEdited, NULL);
- MCMovieChanged(theMC, myMovie);
- }